/****************************************************************************
 * decode.v
 ****************************************************************************/
`include "defines.v"

/**
 * Module: decode
 * 
 * 所有信号遵从正逻辑，即信号电平为1的含义与信号变量名称的含义一致，如rst信号
 * 为1代表复位，0代表复位信号无效，系统正常工作
 *
 * 指令的译码模块，将ifu传递过来经过初步解码的指令进行深度解析
 * 解码输出：
        1、指令的执行单元，指令需要派遣给哪个执行单元信息
        2、指令的详细信息（是具体哪个指令），用于具体的运算单元判断要执行的具体内容
        3、指令的源、目的操作寄存器、及对应的使能信号（因指令架构无目的寄存器操作数，所以实际译码输出没有目的寄存器信息）
        4、指令的立即数，并将立即数进行相应的扩展
    上面四个输出信号组的部分执行内容可以放在执行单元也可以放在译码单元，但是考虑放在译码单元可以复用部分逻辑，节省资源。

 * 指令译码单元全部是组合逻辑实现
 */

module decode
(
    // 前端取指单元ifu相关接口，dec模块为纯组合逻辑，因为与前后端均无req、ack等握手信号
    input                                 ifu2dec_instr_jmp,      // 无条件跳转指令
    input                                 ifu2dec_instr_bjp,      // 条件跳转指令
    input [`CODE_WIDTH-1 : 0]             ifu2dec_instr,          // 指令除了op1剩余的部分
    input [`CODE_ADDR_WIDTH-1 : 0]        ifu2dec_pc              // 当前指令的pc值

    // 译码单元与后端执行单元exu的接口信号
    output                                dec2exu_rglr,           // 普通运算指令单元
    output                                dec2exu_lsu,            // 访存指令单元
    output                                dec2exu_bjp,            // 分支预测指令单元
    output                                dec2exu_csr,            // CSR读写指令单元
    output                                dec2exu_long,           // 长周期运算指令单元
    output                                dec2exu_ctrl,           // 控制类指令单元

    output                                dec2exu_regfile_rd1_en, // 寄存器文件读端口1读使能
    output                                dec2exu_regfile_rd2_en, // 寄存器文件读端口2读使能
    output [`REG_ID_WIDTH-1 : 0]          dec2exu_regfile_rd1_idx,// 寄存器文件读端口1的idx
    output [`REG_ID_WIDTH-1 : 0]          dec2exu_regfile_rd2_idx,// 寄存器文件读端口2的idx

    output                                dec2exu_regfile_wr_en,  //寄存器文件写使能
    output [`REG_ID_WIDTH-1 : 0]          dec2exu_regfile_wr_idx, //寄存器文件写端口的idx

    output                                dec2exu_need_imm，      // 需要立即数参与执行
    output [`CODE_WIDTH-1 : 0]            dec2exu_imm_b16,        /* 16位立即数，部分单元需要将指令扩展为32位，
                                                                     由对应的单元自行扩展，译码模块不做处理 */

    output [`INSTR_INFO_BUS_WIDTH-1 : 0]  dec2exu_instr_info      // 解析出来的具体的指令信息
);
	

    // 对完整的指令进行解析，拆分出不同格式的操作码部分
    wire sub_op1_b2 = ifu2dec_instr[`CODE_WIDTH-1 : `CODE_WIDTH-2];
    wire sub_op2_b2 = ifu2dec_instr[`CODE_WIDTH-3 : `CODE_WIDTH-4];
    wire sub_op2_b4 = ifu2dec_instr[`CODE_WIDTH-3 : `CODE_WIDTH-6];
    wire sub_op3_b2 = ifu2dec_instr[`CODE_WIDTH-5 : `CODE_WIDTH-6];
    

    // 对完整的指令进行解析，拆分出不同的源操作数，目的操作数部分（暂无）
    wire src_a_z5    = ifu2dec_instr[`CODE_WIDTH-7 : `CODE_WIDTH-11];
    wire src_a_imm10 = ifu2dec_instr[`CODE_WIDTH-7 : 0];
    wire src_a_imm5  = src_a_z5;
    wire src_a_r5    = src_a_z5;
    wire src_a_imm12 = ifu2dec_instr[`CODE_WIDTH-5 : 0];
    wire src_a_r2    = ifu2dec_instr[`CODE_WIDTH-7 : `CODE_WIDTH-8];

    wire src_b_z5    = ifu2dec_instr[4:0];
    wire src_b_r5    = src_b_z5;
    wire src_b_imm5  = src_b_z5;
    wire src_b_imm8  = ifu2dec_instr[7:0];


    // 对指令操作码进行基本的逻辑判断
    wire sub_op1_b2_00 = sub_op1_b2 == 2'b00;
    // wire sub_op1_b2_01 = sub_op1_b2 == 2'b01;
    wire sub_op1_b2_10 = sub_op1_b2 == 2'b10;
    wire sub_op1_b2_11 = sub_op1_b2 == 2'b11;

    wire sub_op2_b2_00 = sub_op2_b2 == 2'b00;
    wire sub_op2_b2_10 = sub_op2_b2 == 2'b10;
    wire sub_op2_b2_01 = sub_op2_b2 == 2'b01;
    wire sub_op2_b2_11 = sub_op2_b2 == 2'b11;

    wire sub_op3_b2_00 = sub_op3_b2 == 2'b00;
    wire sub_op3_b2_01 = sub_op3_b2 == 2'b01;
    wire sub_op3_b2_10 = sub_op3_b2 == 2'b10;
    wire sub_op3_b2_11 = sub_op3_b2 == 2'b11;

    wire sub_op2_b4_0000 = sub_op2_b4 == 4'b0000;
    wire sub_op2_b4_0001 = sub_op2_b4 == 4'b0001;
    wire sub_op2_b4_0010 = sub_op2_b4 == 4'b0010;
    wire sub_op2_b4_0011 = sub_op2_b4 == 4'b0011;
    wire sub_op2_b4_0100 = sub_op2_b4 == 4'b0100;
    wire sub_op2_b4_0101 = sub_op2_b4 == 4'b0101;
    wire sub_op2_b4_0110 = sub_op2_b4 == 4'b0110;
    wire sub_op2_b4_0111 = sub_op2_b4 == 4'b0111;
    wire sub_op2_b4_1000 = sub_op2_b4 == 4'b1000;
    wire sub_op2_b4_1001 = sub_op2_b4 == 4'b1001;
    wire sub_op2_b4_1010 = sub_op2_b4 == 4'b1010;
    wire sub_op2_b4_1011 = sub_op2_b4 == 4'b1011;
    wire sub_op2_b4_1100 = sub_op2_b4 == 4'b1100;
    wire sub_op2_b4_1101 = sub_op2_b4 == 4'b1101;
    wire sub_op2_b4_1110 = sub_op2_b4 == 4'b1110;
    wire sub_op2_b4_1111 = sub_op2_b4 == 4'b1111;


    // 按指令类型对指令进行解析
    wire type_2_2_2_5z_5z = sub_op1_b2_00 & sub_op2_b2_00 & sub_op3_b2_00;
    wire type_2_2_2_10i   = sub_op1_b2_00 & sub_op2_b2_00 & sub_op3_b2_01;
    wire type_2_2_2_5i_5z = sub_op1_b2_00 & sub_op2_b2_01 & (~sub_op3_b2[1]);
    wire type_2_2_2_5r_5z = sub_op1_b2_00 & sub_op2_b2_01 & sub_op3_b2[1];
    wire type_2_2_12i     = sub_op1_b2_01;
    // 下面的几个逻辑均用到了sub_op2_b2的逻辑判断结果，是因为sub_op2_b2等价于sub_op2_b4[3:2]
    // 例如：sub_op2_b2_11 等价于 sub_op2_b4[3:2] == 2'b11
    wire type_2_4_5r_5r   = (sub_op1_b2_10 & (~sub_op2_b2_11)) | (sub_op1_b2_11 & sub_op2_b2_11);       
    wire type_2_4_5r_5i   = (sub_op1_b2_10 & sub_op2_b2_11) | (sub_op1_b2_11 & (sub_op2_b2_00 | sub_op2_b4_0100));
    wire type_2_4_2r_8i   = sub_op1_b2_11 & sub_op2_b2_10;


    // 解析出指令具体要ALU哪个模块执行的信息
    assign dec2exu_rglr = (sub_op1_b2_10 & type_2_4_5r_5r) | type_2_4_5r_5i;
    assign dec2exu_lsu  = type_2_4_2r_8i;
    assign dec2exu_bjp  = type_2_2_12i;
    assign dec2exu_csr  = type_2_2_2_5i_5z | type_2_2_2_5r_5z;
    assign dec2exu_long = sub_op1_b2_11 & type_2_4_5r_5r;
    assign dec2exu_ctrl = type_2_2_2_5z_5z | type_2_2_2_10i;


    // 解析出指令是否要读取寄存器文件，以及要使用寄存器的哪个读端口
    assign dec2exu_regfile_rd1_en  = type_2_2_2_5r_5z
                                   | type_2_4_5r_5r
                                   | type_2_4_5r_5i
                                   | type_2_4_2r_8i;
    assign dec2exu_regfile_rd2_en  = type_2_4_5r_5r;
    /* 
      寄存器读端口1的idx生成比较特殊，因为LSU的寄存器idx只有2bit，与标准的5bit寄存器idx不一致
      架构规定，当指令为LH/SH时，2bit的idx对应寄存器AL,BL,CL,DL，因此高位扩展000成为标准5bit寄存器idx
               当指令为LW/SW时，5bit的idx对应寄存器AX,BX,CX,DX，因此高位扩展110成为标准5bit寄存器idx
     */
    assign dec2exu_regfile_rd1_idx = (dec2exu_lsu & (~sub_op2_b4[1]))  ? {3'b000, src_a_r2}
                                   : (dec2exu_lsu & sub_op2_b4[1])     ? {3'b110, src_a_r2}
                                   : src_a_r5;
    assign dec2exu_regfile_rd2_idx = src_b_r5;

    // TODO

    // 对立即数解析，共用一套立即数总线，包括：LUI指令、rglr部分含立即数的指令、lsu指令、csr指令、bjp指令
    assign dec2exu_need_imm = type_2_2_2_10i
                            | type_2_2_2_5i_5z
                            | type_2_2_12i
                            | type_2_4_5r_5i
                            | type_2_4_2r_8i;

    assign dec2exu_imm_b16[11:0] = ({12{type_2_2_2_10i}}   & {2'b0, src_a_imm10})
                                 | ({12{type_2_2_2_5i_5z}} & {7'b0, src_a_imm5})
                                 | ({12{type_2_2_12i}}     & src_a_imm12)
                                 | ({12{type_2_4_5r_5i}}   & {7'b0, src_b_imm5})
                                 | ({12{type_2_4_2r_8i}}   & {4'b0, src_b_imm8});
    assign dec2exu_imm_b16[15:12] = 4'b0;


    // 解析具体的指令信息，生成指令信息总线
    // rglr模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_rglr;
    assign instr_info_rglr[`INSTR_INFO_RGLR_ADD]  = sub_op1_b2_10 & (sub_op2_b4_0000 | sub_op2_b4_1100);
    assign instr_info_rglr[`INSTR_INFO_RGLR_SUB]  = sub_op1_b2_10 & sub_op2_b4_0001;
    assign instr_info_rglr[`INSTR_INFO_RGLR_SLT]  = sub_op1_b2_10 & (sub_op2_b4_0010 | sub_op2_b4_1101);
    assign instr_info_rglr[`INSTR_INFO_RGLR_SLTU] = sub_op1_b2_10 & (sub_op2_b4_0011 | sub_op2_b4_1110);
    assign instr_info_rglr[`INSTR_INFO_RGLR_SLL]  = sub_op1_b2_10 & (sub_op2_b4_0100 | sub_op2_b4_1111);
    assign instr_info_rglr[`INSTR_INFO_RGLR_SRL]  = (sub_op1_b2_10 & sub_op2_b4_0101) | (sub_op2_b2_11 & sub_op2_b4_0000);
    assign instr_info_rglr[`INSTR_INFO_RGLR_SRA]  = (sub_op1_b2_10 & sub_op2_b4_0110) | (sub_op2_b2_11 & sub_op2_b4_0001);
    assign instr_info_rglr[`INSTR_INFO_RGLR_XOR]  = (sub_op1_b2_10 & sub_op2_b4_0111) | (sub_op2_b2_11 & sub_op2_b4_0010);
    assign instr_info_rglr[`INSTR_INFO_RGLR_OR]   = (sub_op1_b2_10 & sub_op2_b4_1000) | (sub_op2_b2_11 & sub_op2_b4_0011);
    assign instr_info_rglr[`INSTR_INFO_RGLR_AND]  = (sub_op1_b2_10 & sub_op2_b4_1001) | (sub_op2_b2_11 & sub_op2_b4_0100);
    assign instr_info_rglr[`INSTR_INFO_RGLR_MUL]  = (sub_op1_b2_10 & sub_op2_b4_1010);
    assign instr_info_rglr[`INSTR_INFO_RGLR_MULU] = (sub_op1_b2_10 & sub_op2_b4_1011);

    // lsu模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_lsu;
    assign instr_info_lsu[`INSTR_INFO_LSU_LH]     = sub_op1_b2_11 & sub_op2_b4_1000;
    assign instr_info_lsu[`INSTR_INFO_LSU_SH]     = sub_op1_b2_11 & sub_op2_b4_1001;
    assign instr_info_lsu[`INSTR_INFO_LSU_LW]     = sub_op1_b2_11 & sub_op2_b4_1010;
    assign instr_info_lsu[`INSTR_INFO_LSU_SW]     = sub_op1_b2_11 & sub_op2_b4_1011;

    // bjp模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_bjp;
    assign instr_info_bjp[`INSTR_INFO_BJP_JALR]   = sub_op1_b2_00 & sub_op2_b2_10;
    assign instr_info_bjp[`INSTR_INFO_BJP_JAL]    = sub_op1_b2_00 & sub_op2_b2_11;
    assign instr_info_bjp[`INSTR_INFO_BJP_BEQ]    = sub_op1_b2_01 & sub_op2_b2_00;
    assign instr_info_bjp[`INSTR_INFO_BJP_BNE]    = sub_op1_b2_01 & sub_op2_b2_01;
    assign instr_info_bjp[`INSTR_INFO_BJP_BLT]    = sub_op1_b2_01 & sub_op2_b2_10;
    assign instr_info_bjp[`INSTR_INFO_BJP_BGE]    = sub_op1_b2_01 & sub_op2_b2_11;
    
    // csr读写模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_csr;
    assign instr_info_csr[`INSTR_INFO_CSR_CSRRS]  = sub_op1_b2_00 & sub_op2_b2_01 & sub_op3_b2_00;
    assign instr_info_csr[`INSTR_INFO_CSR_CSRRC]  = sub_op1_b2_00 & sub_op2_b2_01 & sub_op3_b2_01;
    assign instr_info_csr[`INSTR_INFO_CSR_CSRRW]  = sub_op1_b2_00 & sub_op2_b2_01 & sub_op3_b2_10;
    assign instr_info_csr[`INSTR_INFO_CSR_CSRRR]  = sub_op1_b2_00 & sub_op2_b2_01 & sub_op3_b2_11;

    // long模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_long;
    assign instr_info_long[`INSTR_INFO_LONG_DIV]  = sub_op1_b2_11 & sub_op2_b4_1100;
    assign instr_info_long[`INSTR_INFO_LONG_SQRT] = sub_op1_b2_11 & sub_op2_b4_1101;
    assign instr_info_long[`INSTR_INFO_LONG_COS]  = sub_op1_b2_11 & sub_op2_b4_1110;

    // ctrl模块指令总线生成
    wire [`INSTR_INFO_BUS_WIDTH-1 : 0]   instr_info_ctrl;
    assign instr_info_ctrl[`INSTR_INFO_CTRL_HLT]  = sub_op1_00 & sub_op2_b2_00 & sub_op3_b2_00;
    assign instr_info_ctrl[`INSTR_INFO_CTRL_LUI]  = sub_op1_00 & sub_op2_b2_00 & sub_op3_b2_01;

    // 多路选择器，根据具体的指令需要送给的运算单元将指令信息总线合并
    assign dec2exu_instr_info = ({`INSTR_INFO_BUS_WIDTH'{dec2exu_rglr}} & instr_info_rglr)
                              | ({`INSTR_INFO_BUS_WIDTH'{dec2exu_lsu}} & instr_info_lsu)
                              | ({`INSTR_INFO_BUS_WIDTH'{dec2exu_bjp}} & instr_info_bjp)
                              | ({`INSTR_INFO_BUS_WIDTH'{dec2exu_csr}} & instr_info_csr)
                              | ({`INSTR_INFO_BUS_WIDTH'{dec2exu_long}} & instr_info_long)
                              | ({`INSTR_INFO_BUS_WIDTH'{dec2exu_ctrl}} & instr_info_ctrl);

endmodule
